﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;
namespace XYZshell.Game.CardGameEngine
{
	/// <summary>
	/// 对象XML解析结果。
	/// </summary>
	public class XObject
	{
		private XmlNode mxml;
		private XObject[] mChilds;

		/// <summary>
		/// 如果在初始化xObject时未传入参数则生成以Object为节点的XML对象。
		/// </summary>
		public XObject()
		{
			Initialize( "<Object/>" );
		}

		/// <summary>
		/// 根据XML文件构造Object实例。
		/// <param name="xml">用于构造对象实例的XML</param>
		/// </summary>
		public XObject( XmlNode xml )
		{
			Initialize( xml );
		}

		/// <summary>
		/// 根据XML文件构造Object实例。
		/// <param name="xml">XML字符串</param>
		/// </summary>
		public XObject( string xml )
		{
			Initialize( xml );
		}

		/// <summary>
		/// 根据XML文件构造Object实例。
		/// <param name="xml">XML字符串</param>
		/// </summary>
		protected void Initialize( string xml )
		{
			XmlDocument lxml = new XmlDocument();
			try
			{
				lxml.LoadXml( xml );
			}
			catch
			{
				throw new Exception( "用于创建对象的XML字符串：\r\n" + xml + "\r\n格式错误，请检查！" + xml );
			}
			Initialize( lxml.LastChild );
		}

		/// <summary>
		/// 根据XML文件构造Object实例。
		/// <param name="xml">用于构造对象实例的XML</param>
		/// </summary>
		protected void Initialize( XmlNode xml )
		{
			mxml = xml;
		}

		/// <summary>
		/// 构成对象的Xml字符串。
		/// </summary>
		public string ToXml
		{
			get
			{
				return "<?xml version = \"1.0\" encoding = \"utf-8\"?>" + mxml.OuterXml;
			}
		}
		public string ToDtdXml( string dtd )
		{
			return "<?xml version = \"1.0\" encoding = \"gb2312\" standalone = \"yes\"?>" + dtd + mxml.OuterXml;
		}

		/// <summary>
		/// 构成对象的Xml字符串。
		/// </summary>
		public string OuterXml
		{
			get
			{
				return mxml.OuterXml;
			}
		}
		/// <summary>
		/// 构成对象的Xml字符串。
		/// </summary>
		public string InnerXml
		{
			get
			{
				return mxml.InnerXml;
			}
		}
		/// <summary>
		/// 表示Object的Xml节点。
		/// </summary>
		public XmlNode Node
		{
			get
			{
				return mxml;
			}
			set
			{
				mxml = value;
			}
		}

		/// <summary>
		/// 属性个数。
		/// </summary>
		public int AttributeCount
		{
			get
			{
				return mxml.Attributes.Count;
			}
		}

		/// <summary>
		/// 子对象个数。
		/// </summary>
		public int ChildCount
		{
			get
			{
				return mxml.ChildNodes.Count;
			}
		}

		/// <summary>
		/// 子对象数组。
		/// </summary>
		public XObject[] Childs
		{
			get
			{
				if (mChilds == null)
				{
					RefreshChilds();
				}
				if (mChilds.Length != mxml.ChildNodes.Count)
				{
					RefreshChilds();
				}
				return mChilds;
			}
		}
		
		/// <summary>
		/// 父级对象。
		/// </summary>
		public XObject Parent
		{
			get
			{
				try
				{
					XObject lParent = new XObject( mxml.ParentNode );
					if (OuterXml != lParent.OuterXml)
						return lParent;
					else
						return null;
				}
				catch
				{
					return null;
				}
			}
		}

		/// <summary>
		/// 紧接着该对象的上一个节点对象。
		/// </summary>
		public XObject PreviousObject
		{
			get
			{
				try
				{
					return new XObject( mxml.PreviousSibling );
				}
				catch
				{
					return null;
				}
			}
		}

		/// <summary>
		/// 紧接着该对象的下一个节点对象。
		/// </summary>
		public XObject NextObject
		{
			get
			{
				try
				{
					return new XObject( mxml.NextSibling );
				}
				catch
				{
					return null;
				}
			}
		}

		/// <summary>
		/// 紧接着该对象的下一个相同类型节点对象。
		/// </summary>
		public XObject NextSame
		{
			get
			{
				XObject next=NextObject;
				while (next.NodeName != NodeName && next.NodeName != null && next.Parent.ToString()==this.Parent.ToString())
				{
					next =next.NextObject;
				}
				return next;
			}
		}


		/// <summary>
		/// 对象名称。
		/// </summary>
		public string Name
		{
			get
			{
				return Attribute( "name" );
			}
			set
			{
				SetAttr( "name", value );
			}
		}

		/// <summary>
		/// 对象类型。
		/// </summary>
		public string Type
		{
			get
			{
				return Attribute( "type" );
			}
			set
			{
				SetAttr( "type", value );
			}
		}

		/// <summary>
		/// 如果对象是简单类型则通过引用Value属性取值。
		/// </summary>
		public string Value
		{
			get
			{
				return Attribute( "value" );
			}
		}

		/// <summary>
		/// 返回子对象的Value数组。
		/// </summary>
		public string[] cValue
		{
			get
			{
				string[] lcValue = new string[Childs.Length];
				for (int i = 0; i < Childs.Length; i++)
				{
					lcValue[i] = Childs[i].Value;
				}
				return lcValue;
			}
		}

		/// <summary>
		/// 返回当前对象在父对象中的索引。
		/// </summary>
		public int Index
		{
			get
			{
				for (int i = 0; i < mxml.ParentNode.ChildNodes.Count; i++)
				{
					if (mxml.ParentNode.ChildNodes[i] == mxml)
						return i;
				}
				return -1;
			}
		}

		/// <summary>
		/// 表示对象的XML节点名称。
		/// </summary>
		public string NodeName
		{
			get
			{
				return mxml.Name;
			}
			set
			{
				XmlNode lOldXml = mxml;
				if (lOldXml.Name == value)
					return;
				if (Parent == null)
				{
					XmlDocument lXmlDocument = new XmlDocument();
					lXmlDocument.LoadXml( "<" + value + "/>" );
					lXmlDocument.LastChild.InnerXml = lOldXml.InnerXml;
					mxml = lXmlDocument.LastChild;
					for (int i = 0; i < lOldXml.Attributes.Count; i++)
					{
						AddAttribute( lOldXml.Attributes[i].Name, lOldXml.Attributes[i].Value );
					}
				}
				else
				{
					Parent.AddChild( Index, new XObject( "<" + value + "/>" ) );
					lOldXml.ParentNode.ChildNodes.Item( Index - 1 ).InnerXml = lOldXml.InnerXml;
					for (int i = 0; i < AttributeCount; i++)
					{
						Parent.Childs[Index - 1].AddAttribute( AttributeName( i ), Attribute( i ) );
					}
					mxml = lOldXml.ParentNode.ChildNodes.Item( Index - 1 );
					lOldXml.ParentNode.RemoveChild( lOldXml );
				}
			}
		}

		/// <summary>
		/// 根据索引取得属性。
		/// <param name="AttributeIndex">属性索引</param>
		/// <returns>属性值</returns>
		/// </summary>
		public string Attribute( int AttributeIndex )
		{
			return mxml.Attributes.Item( AttributeIndex ).Value;
		}

		public string AttributeName( int AttributeIndex )
		{
			return mxml.Attributes.Item( AttributeIndex ).Name;
		}

		/// <summary>
		/// 根据名称取得属性。
		/// <param name="AttributeName">属性名称</param>
		/// <returns>属性值</returns>
		/// </summary>
		public string Attribute( string attributeName )
		{
			try
			{
				for (int i = 0; i < AttributeCount; i++)
				{
					if (AttributeName( i ).ToUpper() == attributeName.ToUpper())
					{
						return Attribute( i );
					}
				}
				return null;
			}
			catch
			{
				return null;
			}
		}

		/// <summary>
		/// 给对象添加属性值。
		/// <param name="AttributeName">属性名称</param>
		/// <param name="AttributeValue">属性值</param>
		/// </summary>
		public void AddAttribute( string attributeName, string attributeValue )
		{
			if (Attribute( attributeName ) == null)
			{
				XmlAttribute lNewAttribute = mxml.OwnerDocument.CreateAttribute( attributeName );
				lNewAttribute.InnerText = attributeValue;
				mxml.Attributes.Append( lNewAttribute );
			}
			else
			{
				throw new Exception( "指定的属性" + attributeName + "在对象中已存在！\r\n对象XML：\r\n" + OuterXml );
			}
		}

		/// <summary>
		/// 给对象的某一属性赋值。
		/// </summary>
		/// <param name="AttributeName">属性名称</param>
		/// <param name="AttributeValue">属性值</param>
		public void SetAttribute( string attributeName, string attributeValue )
		{
			try
			{
				for (int i = 0; i < AttributeCount; i++)
				{
					if (AttributeName( i ) == attributeName)
					{
						mxml.Attributes[i].Value = attributeValue;
					}
				}
			}
			catch
			{
				throw new Exception( "指定的属性" + attributeName + "在对象中不存在！\r\n对象XML：\r\n" + OuterXml );
			}
		}

		/// <summary>
		/// 给对象的某一属性赋值。
		/// </summary>
		/// <param name="attributeName">属性名称</param>
		/// <param name="attributeValue">属性值</param>
		public void SetAttr( string attributeName, string attributeValue )
		{
			if (Attribute( attributeName ) != null)
			{
				SetAttribute( attributeName, attributeValue );
			}
			else
			{
				AddAttribute( attributeName, attributeValue );
			}
		}

		public void SetAttr( string attributeName, int attributeValue )
		{
			SetAttr( attributeName, attributeValue.ToString() );
		}

		/// <summary>
		/// 给对象添加子对象。
		/// </summary>
		/// <param name="Childs">待添加的子对象数组</param>
		public void AddChild( params XObject[] NewChilds )
		{
			XObject lChild = null;
			for (int i = 0; i < NewChilds.Length; i++)
			{
				lChild = NewChilds[i];
				if (lChild == null)
					return;
				XmlNode lNewChild = (XmlNode)mxml.OwnerDocument.CreateElement( "NewChild" );
				lNewChild.InnerXml = lChild.OuterXml;
				mxml.AppendChild( lNewChild.LastChild );
			}
		}

		/// <summary>
		/// 给对象添加子对象
		/// </summary>
		/// <param name="Index">添加位置索引</param>
		/// <param name="NewChild">待添加的子对象</param>
		public void AddChild( int index, XObject NewChild )
		{
			if (Childs.Length < index)
				throw new Exception( "指定的索引号不存在，无法插入子对象！" );
			if (mxml.GetType().ToString() == "System.Xml.XmlDocument")
				throw new Exception( "不能在此层插入节点。" );
			if (NewChild == null)
				return;
			XmlNode lNewChild = mxml.OwnerDocument.CreateElement( "NewChild" );
			lNewChild.InnerXml = NewChild.OuterXml;
			if (Childs.Length == 0)
				mxml.AppendChild( lNewChild.LastChild );
			else
			{
				if (index == 0)
					mxml.InsertBefore( lNewChild.LastChild, mxml.ChildNodes.Item( 0 ) );
				else
					mxml.InsertAfter( lNewChild.LastChild, mxml.ChildNodes.Item( index - 1 ) );
			}
		}

		/// <summary>
		/// 通过属性名称和属性值查找对象的下一级子对象
		/// </summary>
		/// <param name="AttributeName">属性名称</param>
		/// <param name="AttributeValue">属性值</param>
		/// <returns>子对象实例</returns>
		public XObject Child( string AttributeName, string AttributeValue )
		{
			for (int i = 0; i < ChildCount; i++)
			{
				if (Child( i ).Attribute( AttributeName ) == AttributeValue)
				{
					return Child( i );
				}
			}
			return null;
		}
		/// <summary>
		/// 通过节点名称查找对象的下一级子对象
		/// </summary>
		/// <param name="nodeName">节点名称</param>
		/// <param name="ignoreCase">是否区分大小写</param>
		/// <returns>subnode entity</returns>
		public XObject Child( string nodeName, bool ignoreCase )
		{
			for (int i = 0; i < ChildCount; i++)
			{
				if (Child( i ).Node.Name == nodeName)
				{
					return Child( i );
				}
			}
			return null;
		}
		/// <summary>
		/// 通过属性名称name和属性值查找对象的下一级子对象
		/// </summary>
		/// <param name="Value">属性值</param>
		/// <returns>子对象实例</returns>
		public XObject Child( string Value )
		{
			return Child( "name", Value );
		}

		/// <summary>
		/// 通过子对象索引获取子对象。
		/// </summary>
		/// <param name="ChildIndex">子对象索引</param>
		/// <returns>子对象实例</returns>
		public XObject Child( int ChildIndex )
		{
			return new XObject( mxml.ChildNodes[ChildIndex] );
		}

		/// <summary>
		/// 移除指定的子节点。
		/// </summary>
		/// <param name="ChildIndex">子节点索引</param>
		public void RemoveChild( int ChildIndex )
		{
			try
			{
				mxml.RemoveChild( mxml.ChildNodes[ChildIndex] );
			}
			catch
			{
				//throw new Exception("属引超出范围，无法移除第" + ChildIndex + 1 + "个子节点！\r\n对象XML：\r\n" + OuterXml);
			}
		}

		/// <summary>
		/// 通过属性名称和属性值查找对象的下一级子对象并移除该子节点。
		/// </summary>
		/// <param name="AttributeName">属性名称</param>
		/// <param name="AttributeValue">属性值</param>
		public void RemoveChild( string AttributeName, string AttributeValue )
		{
			for (int i = 0; i < Childs.Length; i++)
			{
				if (Childs[i].Attribute( AttributeName ) == AttributeValue)
				{
					RemoveChild( i );
				}
			}
		}

		/// <summary>
		/// 通过属性名称name和属性值查找对象的下一级子对象并移除该子节点。
		/// </summary>
		/// <param name="AttributeValue">属性值</param>
		public void RemoveChild( string Value )
		{
			RemoveChild( "name", Value );
		}

		/// <summary>
		/// 移除所有子对象。
		/// </summary>
		public void RemoveAllChild()
		{
			mxml.InnerXml = "";
		}

		/// <summary>
		/// 根据mxml刷新mChilds数组。
		/// </summary>
		private void RefreshChilds()
		{
			//构造子对象数组。
			XObject[] lChilds = new XObject[mxml.ChildNodes.Count];
			for (int i = 0; i < mxml.ChildNodes.Count; i++)
			{
				XObject lChild = new XObject( mxml.ChildNodes[i] );
				lChilds[i] = lChild;
			}
			mChilds = lChilds;
		}
		public override string ToString()
		{
			return this.OuterXml;
		}
	}
}
